#include <jni.h>
#include "audio-opensl.h"
#include "log-print.h"
#include<pthread.h>

extern "C" {
//编码
#include<libavcodec/avcodec.h>
//封装格式处理
#include<libavformat/avformat.h>
#include<libswresample/swresample.h>
//像素处理
#include<libswscale/swscale.h>
#include<SLES/OpenSLES.h>
#include<SLES/OpenSLES_Android.h>

//用SLObjectItf声明引擎接口对象
SLObjectItf engineObject = nullptr;
//声明具体的引擎对象
SLEngineItf engineEngine = nullptr;

//用SLObjectItf创建混音器接口对象
SLObjectItf outputMixObject = nullptr;
//具体的混音器对象实例
SLEnvironmentalReverbItf outputMixEnvironmentalReverb = nullptr;
//默认情况
SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_DEFAULT;

//用SLObjectItf声明播放器接口对象
SLObjectItf audio_player = nullptr;
//播放器接口
SLPlayItf slPlayItf = nullptr;
//缓冲区队列接口
SLAndroidSimpleBufferQueueItf bufferQueueItf = nullptr;

//作用域为私有
static AudioInfo *audioInfo;

size_t buffer_size = 0;
void *buffer;

JavaVM *glJavaVM;
jobject glObj;

pthread_t pthreadId;

void* thread_callback(void *args) {

    return nullptr;
}

//将pcm数据添加到缓冲区中
void getQueueCallBack(SLAndroidSimpleBufferQueueItf slBufferQueueItf, void *context) {
    buffer_size = 0;
    ALOGD("%s", "getPcm---start");
    getPcm(&buffer, &buffer_size);
    ALOGD("%s", "getPcm---end");
    if (buffer != nullptr && buffer_size != 0) {
        //将得到的数据加入到队列中
        (*slBufferQueueItf)->Enqueue(slBufferQueueItf, buffer, buffer_size);
        ALOGD("%s", "----callback----");

        //回调到Java层
        JNIEnv *glEnv;
        if (glJavaVM != nullptr) {
            jint status = glJavaVM->GetEnv((void **)&glEnv, JNI_VERSION_1_6);
            if (status != JNI_OK) {
                glEnv = nullptr;
            }
            if (glEnv != nullptr && glObj != nullptr) {
                jclass clazz = glEnv->GetObjectClass(glObj);
                jmethodID methodId = glEnv->GetMethodID(clazz, "playAudioCallback", "()V");
                glEnv->CallVoidMethod(glObj, methodId);
                glEnv = nullptr;
            }
        }
    }
}

//创建引擎
void createEngine() {
   //创建引擎
   slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr);
   //实现engineObject接口对象
   (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
   //通过引擎调用接口初始化SLEngineItf
   (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
}

//创建混音器
void createMixVolume() {
   //用引擎对象创建混音器接口对象
   (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, nullptr, JNI_FALSE);
   //实现混音器接口对象
   (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
   //利用混音器实例对象接口初始化具体的混音器对象
   SLresult sl_result = (*outputMixObject)->GetInterface(outputMixObject,
                                                         SL_IID_ENVIRONMENTALREVERB,
                                                         &outputMixEnvironmentalReverb);
   //设置
   if (SL_RESULT_SUCCESS == sl_result) {
      (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(
              outputMixEnvironmentalReverb, &settings);
   }
}

//创建播放器
void createPlayer(JNIEnv *env, jstring path) {
   //初始化ffmpeg
   unsigned int rate;
   unsigned int channels;
   createFFmpeg(env, (int *) &rate, (int *) &channels, path);
   audioInfo = getAudioInfo();

   /**
    * typedef struct SLDataLocator_AndroidBufferQueue_ {
             SLuint32    locatorType;//缓冲区队列类型
             SLuint32    numBuffers;//buffer位数
       }
    */
   SLDataLocator_AndroidBufferQueue android_queue = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};

   /**
      typedef struct SLDataFormat_PCM_ {
           SLuint32 		formatType;  pcm
           SLuint32 		numChannels;  通道数
           SLuint32 		samplesPerSec;  采样率
           SLuint32 		bitsPerSample;  采样位数
           SLuint32 		containerSize;  包含位数
           SLuint32 		channelMask;     立体声
           SLuint32		endianness;    end标志位
       } SLDataFormat_PCM;
   */
   SLDataFormat_PCM pcm = {
           SL_DATAFORMAT_PCM,
           channels,
           rate * 1000,
           SL_PCMSAMPLEFORMAT_FIXED_16,
           SL_PCMSAMPLEFORMAT_FIXED_16,
           SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
           SL_BYTEORDER_LITTLEENDIAN
   };

   /**
     typedef struct SLDataSource_ {
           void *pLocator;//缓冲区队列
           void *pFormat;//数据样式,配置信息
       } SLDataSource;
    * */
   SLDataSource dataSource = {&android_queue, &pcm};
   SLDataLocator_OutputMix slDataLocator_outputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
   SLDataSink slDataSink = {&slDataLocator_outputMix, nullptr};

   const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND, SL_IID_VOLUME};
   const SLboolean req[3] = {SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE};

   /**
    * SLresult (*CreateAudioPlayer) (
       SLEngineItf self,
       SLObjectItf * pPlayer,
       SLDataSource *pAudioSrc,//数据设置
       SLDataSink *pAudioSnk,//关联混音器
       SLuint32 numInterfaces,
       const SLInterfaceID * pInterfaceIds,
       const SLboolean * pInterfaceRequired
      );
    * */
   (*engineEngine)->CreateAudioPlayer(engineEngine, &audio_player, &dataSource, &slDataSink, 3, ids,
                                      req);

   (*audio_player)->Realize(audio_player, SL_BOOLEAN_FALSE);
   //初始化播放器
   (*audio_player)->GetInterface(audio_player, SL_IID_PLAY, &slPlayItf);
   //注册缓冲区,通过缓冲区里面的数据进行播放
   (*audio_player)->GetInterface(audio_player, SL_IID_BUFFERQUEUE, &bufferQueueItf);
   //设置回调接口
   (*bufferQueueItf)->RegisterCallback(bufferQueueItf, getQueueCallBack, nullptr);
   //播放
   (*slPlayItf)->SetPlayState(slPlayItf, SL_PLAYSTATE_PLAYING);
   //开始播放
   getQueueCallBack(bufferQueueItf, nullptr);

   //创建线程
   pthread_create(&pthreadId, nullptr, thread_callback, nullptr);
   pthread_join(pthreadId, nullptr);
}

//释放资源
void releaseResource() {
   if (audio_player != nullptr) {
      (*audio_player)->Destroy(audio_player);
      audio_player = nullptr;
      bufferQueueItf = nullptr;
      slPlayItf = nullptr;
   }

   if (outputMixObject != nullptr) {
      (*outputMixObject)->Destroy(outputMixObject);
      outputMixObject = nullptr;
      outputMixEnvironmentalReverb = nullptr;
   }

   if (engineObject != nullptr) {
      (*engineObject)->Destroy(engineObject);
      engineObject = nullptr;
      engineEngine = nullptr;
   }
}

JNIEXPORT void JNICALL
Java_com_hengfoxwolf_ffmpegdemo_util_AudioSLPlayer_play(JNIEnv *env, jobject obj, jstring path) {
   //创建引擎
   createEngine();
   //创建混音器
   createMixVolume();
   //创建播放器
   createPlayer(env, path);
}


JNIEXPORT void JNICALL
Java_com_hengfoxwolf_ffmpegdemo_util_AudioSLPlayer_init(JNIEnv *env, jobject obj) {
    env->GetJavaVM(&glJavaVM);
    glObj = env->NewGlobalRef(obj);
}

JNIEXPORT void JNICALL
Java_com_hengfoxwolf_ffmpegdemo_util_AudioSLPlayer_stop(JNIEnv *env, jobject obj) {
   releaseResource();
}

JNIEXPORT void JNICALL
Java_com_hengfoxwolf_ffmpegdemo_util_AudioSLPlayer_playPause(JNIEnv *env, jobject obj,
                                                       jboolean play_pause) {
    //暂停音乐
    if (nullptr != slPlayItf) {
        SLuint32 state = play_pause ? SL_PLAYSTATE_PAUSED : SL_PLAYSTATE_PLAYING;
        (*slPlayItf)->SetPlayState(slPlayItf, state);
    }
}

JNIEXPORT void JNICALL
Java_com_hengfoxwolf_ffmpegdemo_util_AudioSLPlayer_seekToPlay(JNIEnv *env, jobject obj,
                                                        jint seek_to_time) {
    auto seek_pos = (int64_t) (seek_to_time /
                               av_q2d(audioInfo->avFormatContext->streams[audioInfo->stream_index]->time_base));
    if (av_seek_frame(audioInfo->avFormatContext,
                      audioInfo->stream_index,
                      seek_pos,
                      AVSEEK_FLAG_BACKWARD) < 0) {
        return;
    }
    avcodec_flush_buffers(audioInfo->avCodecContext);
}

JNIEXPORT void JNICALL
Java_com_hengfoxwolf_ffmpegdemo_util_AudioSLPlayer_destroy(JNIEnv *env, jobject thiz) {
    releaseFFmpeg();

    glObj = nullptr;
    glJavaVM->DestroyJavaVM();
    glJavaVM = nullptr;
}

}